home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
MPW_TOOL
/
TOOLS
/
TOOLS_WI
/
ICON_8
/
ICONX_FO
/
RMISC.C
< prev
next >
Wrap
Text File
|
1990-04-01
|
52KB
|
2,032 lines
/*
* File: rmisc.c
* Contents: deref, eq, [gcvt], getvar, hash, outimage, [qsort],
* qtos, trace, pushact, popact, topact, [dumpact], putpos, putsub, putint,
* findline, findipc, findfile, [llqsort], doimage, prescan, getimage
* printable.
*
* Integer overflow checking.
*/
#ifdef IconAlloc
#define free mem_free
#endif /* IconAlloc */
#include <math.h>
#include "::h:config.h"
#include "::h:rt.h"
#include "rproto.h"
#include <ctype.h>
/*
* Prototypes.
*/
hidden novalue listimage
Params((FILE *f,struct b_list *lp, int restrict));
hidden novalue printimage Params((FILE *f,int c,int q));
#ifdef IconQsort
hidden novalue qswap Params((char *a, char *b, int w));
#endif /* IconQsort */
hidden novalue showlevel Params((int n));
hidden novalue showline Params((char *f,int l));
/*
* deref - dereference a descriptor.
*/
int deref(dp)
dptr dp;
{
register uword hn;
register union block *bp;
struct descrip v, tref;
union block *tbl;
if (!Tvar(*dp))
/*
* An ordinary variable is being dereferenced; just replace
* *dp with the descriptor *dp is pointing to.
*/
*dp = *(dptr)((word *)VarLoc(*dp) + Offset(*dp));
else switch (Type(*dp)) {
case T_Tvsubs:
/*
* A substring trapped variable is being dereferenced.
* Point bp to the trapped variable block and v to
* the string.
*/
bp = TvarLoc(*dp);
v = bp->tvsubs.ssvar;
if (DeRef(v) == Error)
return Error;
if (!Qual(v))
RetError(103, v);
if (bp->tvsubs.sspos + bp->tvsubs.sslen - 1 > StrLen(v))
RetError(-205, nulldesc);
/*
* Make a descriptor for the substring by getting the
* length and pointing into the string.
*/
StrLen(*dp) = bp->tvsubs.sslen;
StrLoc(*dp) = StrLoc(v) + bp->tvsubs.sspos - 1;
break;
case T_Tvtbl:
if (BlkLoc(*dp)->tvtbl.title == T_Telem) {
/*
* The tvtbl has been converted to a telem and is
* in the table. Replace the descriptor pointed to
* by dp with the value of the element.
*/
*dp = BlkLoc(*dp)->telem.tval;
break;
}
/*
* Point tbl to the table header block, tref to the
* subscripting value, and bp to the appropriate
* chain. Point dp to a descriptor for the default
* value in case the value referenced by the subscript
* is not in the table.
*/
tbl = BlkLoc(*dp)->tvtbl.clink;
tref = BlkLoc(*dp)->tvtbl.tref;
hn = BlkLoc(*dp)->tvtbl.hashnum;
*dp = tbl->table.defvalue;
bp = *(hchain((union block *)tbl, hn));
/*
* Traverse the element chain looking for the subscript
* value. If found, replace the descriptor pointed to
* by dp with the value of the element.
*/
while (bp != NULL && bp->telem.hashnum <= hn) {
if ((bp->telem.hashnum == hn) &&
(equiv(&bp->telem.tref, &tref))) {
*dp = bp->telem.tval;
break;
}
bp = bp->telem.clink;
}
break;
case T_Tvkywd:
bp = TvarLoc(*dp);
*dp = bp->tvkywd.kyval;
break;
default:
syserr("deref: illegal trapped variable");
}
#ifdef DeBugIconx
if (Var(*dp))
syserr("deref: didn't get dereferenced");
#endif /* DeBugIconx */
return Success;
}
#ifdef IconGcvt
/*
* gcvt - Convert number to a string in buf. If possible, ndigit
* significant digits are produced, otherwise a form with an exponent is used.
*
* The name is actually #defined as "icon_gcvt" in config.h.
*/
char *gcvt(number, ndigit, buf)
double number;
int ndigit;
char *buf;
{
int sign, decpt;
register char *p1, *p2;
register i;
p1 = ecvt(number, ndigit, &decpt, &sign);
p2 = buf;
if (sign)
*p2++ = '-';
for (i=ndigit-1; i>0 && p1[i]=='0'; i--)
ndigit--;
if (decpt >= 0 && decpt-ndigit > 4
|| decpt < 0 && decpt < -3) { /* use E-style */
decpt--;
*p2++ = *p1++;
*p2++ = '.';
for (i=1; i<ndigit; i++)
*p2++ = *p1++;
*p2++ = 'e';
if (decpt<0) {
decpt = -decpt;
*p2++ = '-';
}
else
*p2++ = '+';
if (decpt/100 > 0)
*p2++ = decpt/100 + '0';
if (decpt/10 > 0)
*p2++ = (decpt%100)/10 + '0';
*p2++ = decpt%10 + '0';
} else {
if (decpt<=0) {
/* if (*p1!='0') */
*p2++ = '0';
*p2++ = '.';
while (decpt<0) {
decpt++;
*p2++ = '0';
}
}
for (i=1; i<=ndigit; i++) {
*p2++ = *p1++;
if (i==decpt)
*p2++ = '.';
}
if (ndigit<decpt) {
while (ndigit++<decpt)
*p2++ = '0';
*p2++ = '.';
}
}
if (p2[-1]=='.')
*p2++ = '0';
*p2 = '\0';
return(buf);
}
#endif /* IconGcvt */
/*
* Get variable descriptor from name.
*/
int getvar(s,vp)
char *s;
dptr vp;
{
register dptr dp;
register dptr np;
register int i;
struct b_proc *bp;
struct pf_marker *fp = pfp;
/*
* Is it a keyword that's a variable?
*/
if (*s == '&') {
if (strcmp(s,"&error") == 0) { /* must put basic one first */
vp->dword = D_Tvkywd;
VarLoc(*vp) = (dptr)&tvky_err;
return Success;
}
else if (strcmp(s,"&pos") == 0) {
vp->dword = D_Tvkywd;
VarLoc(*vp) = (dptr)&tvky_pos;
return Success;
}
else if (strcmp(s,"&random") == 0) {
vp->dword = D_Tvkywd;
VarLoc(*vp) = (dptr)&tvky_ran;
return Success;
}
else if (strcmp(s,"&subject") == 0) {
vp->dword = D_Tvkywd;
VarLoc(*vp) = (dptr)&tvky_sub;
return Success;
}
else if (strcmp(s,"&trace") == 0) {
vp->dword = D_Tvkywd;
VarLoc(*vp) = (dptr)&tvky_trc;
return Success;
}
else return Failure;
}
/*
* Look for the variable with the name of the local identifiers,
* parameters, and static names in each Icon procedure frame on the stack.
* If not found among the locals, check the global variables.
* If a variable with name is found, variable() returns a variable
* descriptor that points to the corresponding value descriptor.
* If no such variable exits, it fails.
*/
/*
* If no procedure has been called (as can happen with icon_call(),
* dont' try to find local identifier.
*/
if (pfp == NULL)
goto glbvars;
dp = argp;
bp = (struct b_proc *)BlkLoc(*dp); /* get address of procedure block */
np = bp->lnames; /* Check the formal parameter names. */
for (i = abs((int)bp->nparam); i > 0; i--) {
dp++;
if (strcmp(s,StrLoc(*np)) == 0) {
vp->dword = D_Var;
VarLoc(*vp) = (dptr)dp;
return Success;
}
np++;
}
dp = &fp->pf_locals[0];
for (i = (int)bp->ndynam; i > 0; i--) { /* Check the local dynamic names. */
if (strcmp(s,StrLoc(*np)) == 0) {
vp->dword = D_Var;
VarLoc(*vp) = (dptr)dp;
return Success;
}
np++;
dp++;
}
dp = &statics[bp->fstatic]; /* Check the local static names. */
for (i = (int)bp->nstatic; i > 0; i--) {
if (strcmp(s,StrLoc(*np)) == 0) {
vp->dword = D_Var;
VarLoc(*vp) = (dptr)dp;
return Success;
}
np++;
dp++;
}
glbvars:
dp = globals; /* Check the global variable names. */
np = gnames;
while (dp < eglobals) {
if (strcmp(s,StrLoc(*np)) == 0) {
vp->dword = D_Var;
VarLoc(*vp) = (dptr)(dp);
return Success;
}
np++;
dp++;
}
return Failure;
}
/*
* hash - compute hash value of arbitrary object for table and set accessing.
*/
uword hash(dp)
dptr dp;
{
register char *s;
register uword i;
register word j, n;
register int *bitarr;
double r;
if (Qual(*dp)) {
/*
* Compute the hash value for the string based on a scaled sum
* of its first ten characters, plus its length.
*/
i = 0;
s = StrLoc(*dp);
j = n = StrLen(*dp);
if (j > 10) /* limit scan to first ten characters */
j = 10;
while (j-- > 0) {
i += *s++ & 0xFF; /* add unsigned version of next char */
i *= 39; /* scale total by a nice prime number */
}
i += n; /* add the (untruncated) string length */
}
else {
switch (Type(*dp)) {
/*
* The hash value of an integer is itself times eight times the golden
* ratio. We do this calculation in fixed point. We don't just use
* the integer itself, for that would give bad results with sets
* having entries that are multiples of a power of two.
*/
case T_Integer:
i = (13255 * (uword)IntVal(*dp)) >> 10;
break;
#ifdef LargeInts
/*
* The hash value of a bignum is based on its length and its
* most and least significant digits.
*/
case T_Bignum:
{
struct b_bignum *b = &BlkLoc(*dp)->bignumblk;
i = ((b->lsd - b->msd) << 16) ^
(b->digits[b->msd] << 8) ^ b->digits[b->lsd];
}
break;
#endif /* LargeInts */
/*
* The hash value of a real number is itself times a constant,
* converted to an unsigned integer. The intent is to scramble
* the bits well, in the case of integral values, and to scale up
* fractional values so they don't all land in the same bin.
* The constant below is 32749 / 29, the quotient of two primes,
* and was observed to work well in empirical testing.
*/
case T_Real:
GetReal(dp,r);
i = r * 1129.27586206896558;
break;
/*
* The hash value of a cset is based on a convoluted combination
* of all its bits.
*/
case T_Cset:
i = 0;
bitarr = BlkLoc(*dp)->cset.bits + CsetSize - 1;
for (j = 0; j < CsetSize; j++) {
i += *bitarr--;
i *= 37; /* better distribution */
}
i %= 1048583; /* scramble the bits */
break;
/*
* The hash value of a list, set, table, or record is its id,
* hashed like an integer.
*/
case T_List:
i = (13255 * BlkLoc(*dp)->list.id) >> 10;
break;
case T_Set:
i = (13255 * BlkLoc(*dp)->set.id) >> 10;
break;
case T_Table:
i = (13255 * BlkLoc(*dp)->table.id) >> 10;
break;
case T_Record:
i = (13255 * BlkLoc(*dp)->record.id) >> 10;
break;
default:
/*
* For other types, use the type code as the hash
* value.
*/
i = Type(*dp);
break;
}
}
return i;
}
#define StringLimit 16 /* limit on length of imaged string */
#define ListLimit 6 /* limit on list items in image */
/*
* outimage - print image of *dp on file f. If restrict is nonzero,
* fields of records will not be imaged.
*/
novalue outimage(f, dp, restrict)
FILE *f;
dptr dp;
int restrict;
{
register word i, j;
register char *s;
register union block *bp, *vp;
char *type;
FILE *fd;
struct descrip q;
extern char *blkname[];
double rresult;
outimg:
if (Qual(*dp)) {
/*
* *dp is a string qualifier. Print StringLimit characters of it
* using printimage and denote the presence of additional characters
* by terminating the string with "...".
*/
i = StrLen(*dp);
s = StrLoc(*dp);
j = Min(i, StringLimit);
putc('"', f);
while (j-- > 0)
printimage(f, *s++, '"');
if (i > StringLimit)
fprintf(f, "...");
putc('"', f);
return;
}
if (Var(*dp) && !Tvar(*dp)) {
/*
* *d is a variable. Print "variable =", dereference it, and
* call outimage to handle the value.
*/
fprintf(f, "(variable = ");
dp = (dptr)((word *)VarLoc(*dp) + Offset(*dp));
outimage(f, dp, restrict);
putc(')', f);
return;
}
switch (Type(*dp)) {
case T_Null:
fprintf(f, "&null");
return;
case T_Integer:
fprintf(f, "%ld", (long)IntVal(*dp));
return;
#ifdef LargeInts
case T_Bignum:
bigprint(f, dp);
return;
#endif /* LargeInts */
case T_Real:
{
char s[30];
struct descrip rd;
GetReal(dp,rresult);
rtos(rresult, &rd, s);
fprintf(f, "%s", StrLoc(rd));
return;
}
case T_Cset:
/*
* Check for distinguished csets by looking at the address of
* of the object to image. If one is found, print its name.
*/
if ((char *)BlkLoc(*dp) == (char *)&k_ascii) {
fprintf(f, "&ascii");
return;
}
else if ((char *)BlkLoc(*dp) == (char *)&k_cset) {
fprintf(f, "&cset");
return;
}
else if ((char *)BlkLoc(*dp) == (char *)&k_digits) {
fprintf(f, "&digits");
return;
}
else if ((char *)BlkLoc(*dp) == (char *)&k_lcase) {
fprintf(f, "&lcase");
return;
}
else if ((char *)BlkLoc(*dp) == (char *)&k_letters) {
fprintf(f, "&letters");
return;
}
else if ((char *)BlkLoc(*dp) == (char *)&k_ucase) {
fprintf(f, "&ucase");
return;
}
/*
* Use printimage to print each character in the cset. Follow
* with "..." if the cset contains more than StringLimit
* characters.
*/
putc('\'', f);
j = StringLimit;
for (i = 0; i < 256; i++) {
if (Testb(i, BlkLoc(*dp)->cset.bits)) {
if (j-- <= 0) {
fprintf(f, "...");
break;
}
printimage(f, (int)i, '\'');
}
}
putc('\'', f);
return;
case T_File:
/*
* Check for distinguished files by looking at the address of
* of the object to image. If one is found, print its name.
*/
if ((fd = BlkLoc(*dp)->file.fd) == stdin)
fprintf(f, "&input");
else if (fd == stdout)
fprintf(f, "&output");
else if (fd == stderr)
fprintf(f, "&errout");
else {
/*
* The file isn't a special one, just print "file(name)".
*/
i = StrLen(BlkLoc(*dp)->file.fname);
s = StrLoc(BlkLoc(*dp)->file.fname);
fprintf(f, "file(");
while (i-- > 0)
printimage(f, *s++, '\0');
putc(')', f);
}
return;
case T_Proc:
/*
* Produce one of:
* "procedure name"
* "function name"
* "record constructor name"
*
* Note that the number of dynamic locals is used to determine
* what type of "procedure" is at hand.
*/
i = StrLen(BlkLoc(*dp)->proc.pname);
s = StrLoc(BlkLoc(*dp)->proc.pname);
switch ((int)BlkLoc(*dp)->proc.ndynam) {
default: type = "procedure"; break;
case -1: type = "function"; break;
case -2: type = "record constructor"; break;
}
fprintf(f, "%s ", type);
while (i-- > 0)
printimage(f, *s++, '\0');
return;
case T_List:
/*
* listimage does the work for lists.
*/
listimage(f, (struct b_list *)BlkLoc(*dp), restrict);
return;
case T_Table:
/*
* Print "table_m(n)" where n is the size of the table.
*/
fprintf(f, "table_%ld(%ld)", (long)BlkLoc(*dp)->table.id,
(long)BlkLoc(*dp)->table.size);
return;
case T_Set:
/*
* print "set_m(n)" where n is the cardinality of the set
*/
fprintf(f,"set_%ld(%ld)",(long)BlkLoc(*dp)->set.id,
(long)BlkLoc(*dp)->set.size);
return;
case T_Record:
/*
* If restrict is nonzero, print "record(n)" where n is the
* number of fields in the record. If restrict is zero, print
* the image of each field instead of the number of fields.
*/
bp = BlkLoc(*dp);
i = StrLen(bp->record.recdesc->proc.recname);
s = StrLoc(bp->record.recdesc->proc.recname);
fprintf(f, "record ");
while (i-- > 0)
printimage(f, *s++, '\0');
fprintf(f, "_%ld", bp->record.id);
j = bp->record.recdesc->proc.nfields;
if (j <= 0)
fprintf(f, "()");
else if (restrict > 0)
fprintf(f, "(%ld)", (long)j);
else {
putc('(', f);
i = 0;
for (;;) {
outimage(f, &bp->record.fields[i], restrict+1);
if (++i >= j)
break;
putc(',', f);
}
putc(')', f);
}
return;
case T_Tvsubs:
/*
* Produce "v[i+:j] = value" where v is the image of the variable
* containing the substring, i is starting position of the substring
* j is the length, and value is the string v[i+:j]. If the length
* (j) is one, just produce "v[i] = value".
*/
bp = BlkLoc(*dp);
dp = VarLoc(bp->tvsubs.ssvar);
if (!Tvar(bp->tvsubs.ssvar))
dp = (dptr)((word *)dp + Offset(bp->tvsubs.ssvar));
if (dp == (dptr)&tvky_sub)
fprintf(f, "&subject");
else outimage(f, dp, restrict);
if (bp->tvsubs.sslen == 1)
fprintf(f, "[%ld]", (long)bp->tvsubs.sspos);
else
fprintf(f, "[%ld+:%ld]", (long)bp->tvsubs.sspos,
(long)bp->tvsubs.sslen);
if (dp == (dptr)&tvky_sub) {
vp = BlkLoc(bp->tvsubs.ssvar);
if (bp->tvsubs.sspos + bp->tvsubs.sslen - 1 >
StrLen(vp->tvkywd.kyval))
return;
StrLen(q) = bp->tvsubs.sslen;
StrLoc(q) = StrLoc(vp->tvkywd.kyval) + bp->tvsubs.sspos - 1;
fprintf(f, " = ");
dp = &q;
goto outimg;
}
else if (Qual(*dp)) {
if (bp->tvsubs.sspos + bp->tvsubs.sslen - 1 > StrLen(*dp))
return;
StrLen(q) = bp->tvsubs.sslen;
StrLoc(q) = StrLoc(*dp) + bp->tvsubs.sspos - 1;
fprintf(f, " = ");
dp = &q;
goto outimg;
}
return;
case T_Tvtbl:
bp = BlkLoc(*dp);
/*
* It is possible that the descriptor that thinks it is pointing
* to a tabel-element trapped variable may actually be pointing
* at a table element block which had been converted from a
* trapped variable. Check for this first and if it is a table
* element block, produce the outimage of its value.
*/
if (bp->tvtbl.title == T_Telem) {
outimage(f, &bp->tvtbl.tval, restrict);
return;
}
/*
* It really was a tvtbl - produce "t[s]" where t is the image of
* the table containing the element and s is the image of the
* subscript.
*/
else {
dp->dword = D_Table;
BlkLoc(*dp) = bp->tvtbl.clink;
outimage(f, dp, restrict);
putc('[', f);
outimage(f, &bp->tvtbl.tref, restrict);
putc(']', f);
return;
}
case T_Tvkywd:
bp = BlkLoc(*dp);
i = StrLen(bp->tvkywd.kyname);
s = StrLoc(bp->tvkywd.kyname);
while (i-- > 0)
putc(*s++, f);
fprintf(f, " = ");
outimage(f, &bp->tvkywd.kyval, restrict);
return;
case T_Coexpr:
fprintf(f, "co-expression_%ld(%ld)",
(long)((struct b_coexpr *)BlkLoc(*dp))->id,
(long)((struct b_coexpr *)BlkLoc(*dp))->size);
return;
case T_External:
fprintf(f, "external(%d)",((struct b_external *)BlkLoc(*dp))->blksize);
return;
default:
if (Type(*dp) <= MaxType)
fprintf(f, "%s", blkname[Type(*dp)]);
else
syserr("outimage: unknown type");
}
}
/*
* printimage - print character c on file f using escape conventions
* if c is unprintable, '\', or equal to q.
*/
static novalue printimage(f, c, q)
FILE *f;
int c, q;
{
if (printable(c)) {
/*
* c is printable, but special case ", ', and \.
*/
switch (c) {
case '"':
if (c != q) goto def;
fprintf(f, "\\\"");
return;
case '\'':
if (c != q) goto def;
fprintf(f, "\\'");
return;
case '\\':
fprintf(f, "\\\\");
return;
default:
def:
putc(c, f);
return;
}
}
/*
* c is some sort of unprintable character. If it one of the common
* ones, produce a special representation for it, otherwise, produce
* its hex value.
*/
switch (c) {
case '\b': /* backspace */
fprintf(f, "\\b");
return;
#if !EBCDIC
case '\177': /* delete */
#else /* !EBCDIC */
case '\x07':
#endif /* !EBCDIC */
fprintf(f, "\\d");
return;
#if !EBCDIC
case '\33': /* escape */
#else /* !EBCDIC */
case '\x27':
#endif /* !EBCDIC */
fprintf(f, "\\e");
return;
case '\f': /* form feed */
fprintf(f, "\\f");
return;
case LineFeed: /* new line */
fprintf(f, "\\n");
return;
#if EBCDIC == 1
case '\x25': /* EBCDIC line feed */
fprintf(f, "\\l");
return;
#endif /* EBCDIC == 1 */
case CarriageReturn: /* carriage return */
fprintf(f, "\\r");
return;
case '\t': /* horizontal tab */
fprintf(f, "\\t");
return;
case '\13': /* vertical tab */
fprintf(f, "\\v");
return;
default: /* hex escape sequence */
fprintf(f, "\\x%02x", ToAscii(c & 0xff));
return;
}
}
/*
* listimage - print an image of a list.
*/
static novalue listimage(f, lp, restrict)
FILE *f;
struct b_list *lp;
int restrict;
{
register word i, j;
register struct b_lelem *bp;
word size, count;
bp = (struct b_lelem *) lp->listhead;
size = lp->size;
if (restrict > 0 && size > 0) {
/*
* Just give indication of size if the list isn't empty.
*/
fprintf(f, "list_%ld(%ld)", (long)lp->id, (long)size);
return;
}
/*
* Print [e1,...,en] on f. If more than ListLimit elements are in the
* list, produce the first ListLimit/2 elements, an ellipsis, and the
* last ListLimit elements.
*/
fprintf(f, "list_%ld = [", (long)lp->id);
count = 1;
i = 0;
if (size > 0) {
for (;;) {
if (++i > bp->nused) {
i = 1;
bp = (struct b_lelem *) bp->listnext;
}
if (count <= ListLimit/2 || count > size - ListLimit/2) {
j = bp->first + i - 1;
if (j >= bp->nslots)
j -= bp->nslots;
outimage(f, &bp->lslots[j], restrict+1);
if (count >= size)
break;
putc(',', f);
}
else if (count == ListLimit/2 + 1)
fprintf(f, "...,");
count++;
}
}
putc(']', f);
}
#ifdef IconQsort
/* qsort(base,nel,width,compar) - quicksort routine
*
* A Unix-compatible public domain quicksort.
* Based on Bentley, CACM 28,7 (July, 1985), p. 675.
*/
novalue qsort(base, nel, w, compar)
char *base;
int nel, w;
int (*compar)();
{
int i, lastlow;
if (nel < 2)
return;
qswap(base, base + w * (rand() % nel), w);
lastlow = 0;
for (i = 1; i < nel; i++)
if ((*compar) (base + w * i, base) < 0)
qswap(base + w * i, base + w * (++lastlow), w);
qswap(base, base + w * lastlow, w);
qsort(base, lastlow, w, compar);
qsort(base + w * (lastlow+1), nel-lastlow-1, w, compar);
}
static novalue qswap(a, b, w) /* swap *a and *b of width w for qsort*/
char *a, *b;
int w;
{
register t;
while (w--) {
t = *a;
*a++ = *b;
*b++ = t;
}
}
#endif /* IconQsort */
/*
* qtos - convert a qualified string named by *dp to a C-style string.
* Put the C-style string in sbuf if it will fit, otherwise put it
* in the string region.
*/
int qtos(dp, sbuf)
dptr dp;
char *sbuf;
{
register word slen;
register char *c;
c = StrLoc(*dp);
slen = StrLen(*dp)++;
if (slen >= MaxCvtLen) {
if (strreq(slen + 1) == Error)
return Error;
if (c + slen != strfree)
StrLoc(*dp) = alcstr(c, slen);
alcstr("",(word)1);
}
else {
StrLoc(*dp) = sbuf;
for ( ; slen > 0; slen--)
*sbuf++ = *c++;
*sbuf = '\0';
}
return Success;
}
/*
* ctrace - procedure named s is being called with nargs arguments, the first
* of which is at arg; produce a trace message.
*/
novalue ctrace(dp, nargs, arg)
dptr dp;
int nargs;
dptr arg;
{
showline(findfile(ipc.opnd), findline(ipc.opnd));
showlevel(k_level);
putstr(stderr, dp);
putc('(', stderr);
while (nargs--) {
outimage(stderr, arg++, 0);
if (nargs)
putc(',', stderr);
}
putc(')', stderr);
putc('\n', stderr);
fflush(stderr);
}
/*
* rtrace - procedure named s is returning *rval; produce a trace message.
*/
novalue rtrace(dp, rval)
dptr dp;
dptr rval;
{
inst t_ipc;
/*
* Compute the ipc of the return instruction.
*/
t_ipc.op = ipc.op - 1;
showline(findfile(t_ipc.opnd), findline(t_ipc.opnd));
showlevel(k_level);
putstr(stderr, dp);
fprintf(stderr, " returned ");
outimage(stderr, rval, 0);
putc('\n', stderr);
fflush(stderr);
}
/*
* failtrace - procedure named s is failing; produce a trace message.
*/
novalue failtrace(dp)
dptr dp;
{
inst t_ipc;
/*
* Compute the ipc of the fail instruction.
*/
t_ipc.op = ipc.op - 1;
showline(findfile(t_ipc.opnd), findline(t_ipc.opnd));
showlevel(k_level);
putstr(stderr, dp);
fprintf(stderr, " failed");
putc('\n', stderr);
fflush(stderr);
}
/*
* strace - procedure named s is suspending *rval; produce a trace message.
*/
novalue strace(dp, rval)
dptr dp;
dptr rval;
{
inst t_ipc;
/*
* Compute the ipc of the suspend instruction.
*/
t_ipc.op = ipc.op - 1;
showline(findfile(t_ipc.opnd), findline(t_ipc.opnd));
showlevel(k_level);
putstr(stderr, dp);
fprintf(stderr, " suspended ");
outimage(stderr, rval, 0);
putc('\n', stderr);
fflush(stderr);
}
/*
* atrace - procedure named s is being resumed; produce a trace message.
*/
novalue atrace(dp)
dptr dp;
{
inst t_ipc;
/*
* Compute the ipc of the instruction causing resumption.
*/
t_ipc.op = ipc.op - 1;
showline(findfile(t_ipc.opnd), findline(t_ipc.opnd));
showlevel(k_level);
putstr(stderr, dp);
fprintf(stderr, " resumed");
putc('\n', stderr);
fflush(stderr);
}
#ifdef Coexpr
/*
* coacttrace -- co-expression is being activated; produce a trace message.
*/
novalue coacttrace(ccp, ncp)
struct b_coexpr *ccp;
struct b_coexpr *ncp;
{
struct b_proc *bp;
inst t_ipc;
bp = (struct b_proc *)BlkLoc(*argp);
/*
* Compute the ipc of the activation instruction.
*/
t_ipc.op = ipc.op - 1;
showline(findfile(t_ipc.opnd), findline(t_ipc.opnd));
showlevel(k_level);
putstr(stderr, &(bp->pname));
fprintf(stderr,"; co-expression_%ld : ", (long)ccp->id);
outimage(stderr, (dptr)(sp - 3), 0);
fprintf(stderr," @ co-expression_%ld\n", (long)ncp->id);
fflush(stderr);
}
/*
* corettrace -- return from co-expression; produce a trace message.
*/
novalue corettrace(ccp, ncp)
struct b_coexpr *ccp;
struct b_coexpr *ncp;
{
struct b_proc *bp;
inst t_ipc;
bp = (struct b_proc *)BlkLoc(*argp);
/*
* Compute the ipc of the coret instruction.
*/
t_ipc.op = ipc.op - 1;
showline(findfile(t_ipc.opnd), findline(t_ipc.opnd));
showlevel(k_level);
putstr(stderr, &(bp->pname));
fprintf(stderr,"; co-expression_%ld returned ", (long)ccp->id);
outimage(stderr, (dptr)(&ncp->es_sp[-3]), 0);
fprintf(stderr," to co-expression_%ld\n", (long)ncp->id);
fflush(stderr);
}
/*
* cofailtrace -- failure return from co-expression; produce a trace message.
*/
novalue cofailtrace(ccp, ncp)
struct b_coexpr *ccp;
struct b_coexpr *ncp;
{
struct b_proc *bp;
inst t_ipc;
bp = (struct b_proc *)BlkLoc(*argp);
/*
* Compute the ipc of the cofail instruction.
*/
t_ipc.op = ipc.op - 1;
showline(findfile(t_ipc.opnd), findline(t_ipc.opnd));
showlevel(k_level);
putstr(stderr, &(bp->pname));
fprintf(stderr,"; co-epression_%ld failed to co-expression_%ld\n",
(long)ccp->id, (long)ncp->id);
fflush(stderr);
}
#endif /* Coexpr */
/*
* showline - print file and line number information.
*/
static novalue showline(f, l)
char *f;
int l;
{
int i;
i = strlen(f);
while (i > 13) {
f++;
i--;
}
if (l > 0)
fprintf(stderr, "%-13s: %4d ",f, l);
else
fprintf(stderr, " : ");
}
/*
* showlevel - print "| " n times.
*/
static novalue showlevel(n)
register int n;
{
while (n-- > 0) {
putc('|', stderr);
putc(' ', stderr);
}
}
/*
* putpos - assign value to &pos
*/
int putpos(dp,bp)
dptr dp;
struct b_tvkywd *bp;
{
#if MACINTOSH && MPW
/* #pragma unused(bp) */
#endif /* MACINTOSH && MPW */
register word l1;
switch (cvint(dp)) {
case T_Integer:
l1 = cvpos(IntVal(*dp), StrLen(k_subject));
if (l1 == CvtFail)
return Failure;
k_pos = l1;
return Success;
default:
RetError(101, *dp);
}
}
/*
* putsub - assign value to &subject
*/
int putsub(dp,bp)
dptr dp;
struct b_tvkywd *bp;
{
#if MACINTOSH && MPW
/* #pragma unused(bp) */
#endif /* MACINTOSH && MPW */
char sbuf[MaxCvtLen];
switch (cvstr(dp, sbuf)) {
case Cvt:
if (strreq(StrLen(*dp)) == Error)
return Error;
StrLoc(*dp) = alcstr(StrLoc(*dp), StrLen(*dp));
/* no break */
case NoCvt:
k_subject = *dp;
k_pos = 1;
return Success;
default:
RetError(103, *dp);
}
}
/*
* putint - assign integer value to keyword
*/
int putint(dp,bp)
dptr dp;
struct b_tvkywd *bp;
{
switch (cvint(dp)) {
case T_Integer:
IntVal(bp->kyval) = IntVal(*dp);
return Success;
default:
RetError(101, *dp);
}
}
#ifdef Coexpr
/*
* pushact - push actvtr on the activator stack of ce
*/
int pushact(ce, actvtr)
struct b_coexpr *ce, *actvtr;
{
struct astkblk *abp = ce->es_actstk, *nabp;
struct actrec *arp;
/*
* If the last activator is the same as this one, just increment
* its count.
*/
if (abp->nactivators > 0) {
arp = &abp->arec[abp->nactivators - 1];
if (arp->activator == actvtr) {
arp->acount++;
return Success;
}
}
/*
* This activator is different from the last one. Push this activator
* on the stack, possibly adding another block.
*/
if (abp->nactivators + 1 > ActStkBlkEnts) {
nabp = alcactiv();
if (nabp == NULL)
return Error;
nabp->astk_nxt = abp;
abp = nabp;
}
abp->nactivators++;
arp = &abp->arec[abp->nactivators - 1];
arp->acount = 1;
arp->activator = actvtr;
ce->es_actstk = abp;
return Success;
}
/*
* popact - pop the most recent activator from the activator stack of ce
* and return it.
*/
struct b_coexpr *popact(ce)
struct b_coexpr *ce;
{
struct astkblk *abp = ce->es_actstk, *oabp;
struct actrec *arp;
struct b_coexpr *actvtr;
/*
* If the current stack block is empty, pop it.
*/
if (abp->nactivators == 0) {
oabp = abp;
abp = abp->astk_nxt;
free((pointer)oabp);
}
if (abp == NULL || abp->nactivators == 0)
syserr("empty activator stack\n");
/*
* Find the activation record for the most recent co-expression.
* Decrement the activation count and if it is zero, pop that
* activation record and decrement the count of activators.
*/
arp = &abp->arec[abp->nactivators - 1];
actvtr = arp->activator;
if (--arp->acount == 0)
abp->nactivators--;
ce->es_actstk = abp;
return actvtr;
}
/*
* topact - return the most recent activator of ce.
*/
struct b_coexpr *topact(ce)
struct b_coexpr *ce;
{
struct astkblk *abp = ce->es_actstk;
if (abp->nactivators == 0)
abp = abp->astk_nxt;
return abp->arec[abp->nactivators-1].activator;
}
#ifdef DeBugIconx
/*
* dumpact - dump an activator stack
*/
novalue dumpact(ce)
struct b_coexpr *ce;
{
struct astkblk *abp = ce->es_actstk;
struct actrec *arp;
int i;
if (abp)
fprintf(stderr, "Ce %ld ", (long)ce->id);
while (abp) {
fprintf(stderr, "--- Activation stack block (%x) --- nact = %d\n",
abp, abp->nactivators);
for (i = abp->nactivators; i >= 1; i--) {
arp = &abp->arec[i-1];
/*for (j = 1; j <= arp->acount; j++)*/
fprintf(stderr, "co-expression_%ld(%d)\n", (long)(arp->activator->id),
arp->acount);
}
abp = abp->astk_nxt;
}
}
#endif /* DeBugIconx */
#endif /* Coexpr */
/*
* findline - find the source line number associated with the ipc
*/
int findline(ipc)
word *ipc;
{
uword ipc_offset;
uword size;
struct ipc_line *base;
extern struct ipc_line *ilines, *elines;
extern word *records;
static two = 2; /* some compilers generate bad code for division
by a constant that is a power of two ... */
if (!InRange(code,ipc,records))
return 0;
ipc_offset = DiffPtrs((char *)ipc,(char *)code);
base = ilines;
size = DiffPtrs((char *)elines,(char *)ilines) / sizeof(struct ipc_line *);
while (size > 1) {
if (ipc_offset >= base[size / two].ipc) {
base = &base[size / two];
size -= size / two;
}
else
size = size / two;
}
return (int)base->line;
}
/*
* findipc - find the first ipc associated with a source-code line number.
*/
int findipc(line)
int line;
{
uword size;
struct ipc_line *base;
extern struct ipc_line *ilines, *elines;
static two = 2; /* some compilers generate bad code for division
by a constant that is a power of two ... */
base = ilines;
size = DiffPtrs((char *)elines,(char *)ilines) / sizeof(struct ipc_line *);
while (size > 1) {
if (line >= base[size / two].line) {
base = &base[size / two];
size -= size / two;
}
else
size = size / two;
}
return base->ipc;
}
/*
* findfile - find source file name associated with the ipc
*/
char *findfile(ipc)
word *ipc;
{
uword ipc_offset;
struct ipc_fname *p;
extern struct ipc_fname *filenms, *efilenms;
extern word *records;
extern char *strcons;
if (!InRange(code,ipc,records))
return "?";
ipc_offset = DiffPtrs((char *)ipc,(char *)code);
for (p = efilenms - 1; p >= filenms; p--)
if (ipc_offset >= p->ipc)
return strcons + p->fname;
fprintf(stderr,"bad ipc/file name table");
fflush(stderr);
c_exit(ErrorExit);
}
#if IntBits == 16
/* Shell sort with some enhancements from Knuth.. */
novalue llqsort(base, nel, width, cmp )
char *base;
int nel;
int width;
int (*cmp)();
{
register long i, j;
long int gap;
int k;
char *p1, *p2, tmp;
for( gap=1; gap <= nel; gap = 3*gap + 1 ) ;
for( gap /= 3; gap > 0 ; gap /= 3 )
for( i = gap; i < nel; i++ )
for( j = i-gap; j >= 0 ; j -= gap ) {
p1 = base + ( j * width);
p2 = base + ((j+gap) * width);
if( (*cmp)( p1, p2 ) <= 0 ) break;
for( k = width; --k >= 0 ;) {
tmp = *p1;
*p1++ = *p2;
*p2++ = tmp;
}
}
}
#endif /* IntBits == 16 */
/*
* doimage(c,q) - allocate character c in string space, with escape
* conventions if c is unprintable, '\', or equal to q.
* Returns number of characters allocated.
*/
doimage(c, q)
int c, q;
{
static char cbuf[5];
if (printable(c)) {
/*
* c is printable, but special case ", ', and \.
*/
switch (c) {
case '"':
if (c != q) goto def;
alcstr("\\\"", (word)(2));
return 2;
case '\'':
if (c != q) goto def;
alcstr("\\'", (word)(2));
return 2;
case '\\':
alcstr("\\\\", (word)(2));
return 2;
default:
def:
cbuf[0] = c;
alcstr(cbuf, (word)(1));
return 1;
}
}
/*
* c is some sort of unprintable character. If it is one of the common
* ones, produce a special representation for it, otherwise, produce
* its hex value.
*/
switch (c) {
case '\b': /* backspace */
alcstr("\\b", (word)(2));
return 2;
#if !EBCDIC
case '\177': /* delete */
#else /* !EBCDIC */
case '\x07': /* delete */
#endif /* !EBCDIC */
alcstr("\\d", (word)(2));
return 2;
#if !EBCDIC
case '\33': /* escape */
#else /* !EBCDIC */
case '\x27': /* escape */
#endif /* !EBCDIC */
alcstr("\\e", (word)(2));
return 2;
case '\f': /* form feed */
alcstr("\\f", (word)(2));
return 2;
case LineFeed: /* new line */
alcstr("\\n", (word)(2));
return 2;
case CarriageReturn: /* return */
alcstr("\\r", (word)(2));
return 2;
case '\t': /* horizontal tab */
alcstr("\\t", (word)(2));
return 2;
case '\13': /* vertical tab */
alcstr("\\v", (word)(2));
return 2;
default: /* hex escape sequence */
sprintf(cbuf, "\\x%02x", c & 0xff);
alcstr(cbuf, (word)(4));
return 4;
}
}
/*
* prescan(d) - return upper bound on length of expanded string. Note
* that the only time that prescan is wrong is when the string contains
* one of the "special" unprintable characters, e.g. tab.
*/
word prescan(d)
dptr d;
{
register word slen, len;
register char *s, c;
s = StrLoc(*d);
len = 0;
for (slen = StrLen(*d); slen > 0; slen--)
#if EBCDIC
#if SASC
if (!isascii(c = (*s++)) || iscntrl(c))
#else /* SASC */
if (!isprint(c = (*s++)))
#endif /* SASC */
#else /* EBCDIC */
if ((c = (*s++)) < ' ' || c >= 0177)
#endif /* EBCDIC */
len += 4;
else if (c == '"' || c == '\\' || c == '\'')
len += 2;
else
len++;
return len;
}
/*
* getimage(dp1,dp2) - return string image of object dp1 in dp2.
*/
int getimage(dp1,dp2)
dptr dp1, dp2;
{
register word len, outlen, rnlen;
register char *s;
register union block *bp;
char *type;
char sbuf[MaxCvtLen];
FILE *fd;
if (Qual(*dp1)) {
/*
* Get some string space. The magic 2 is for the double quote at each
* end of the resulting string.
*/
if (strreq(prescan(dp1) + 2) == Error)
return Error;
len = StrLen(*dp1);
s = StrLoc(*dp1);
outlen = 2;
/*
* Form the image by putting a quote in the string space, calling
* doimage with each character in the string, and then putting
* a quote at then end. Note that doimage directly writes into the
* string space. (Hence the indentation.) This techinique is used
* several times in this routine.
*/
StrLoc(*dp2) = alcstr("\"", (word)(1));
while (len-- > 0)
outlen += doimage(*s++, '"');
alcstr("\"", (word)(1));
StrLen(*dp2) = outlen;
return Success;
}
switch (Type(*dp1)) {
case T_Null:
StrLoc(*dp2) = "&null";
StrLen(*dp2) = 5;
return Success;
#ifdef LargeInts
case T_Bignum:
{
word slen;
word dlen;
slen = (BlkLoc(*dp1)->bignumblk.lsd - BlkLoc(*dp1)->bignumblk.msd + 1);
dlen = slen * NB * 0.3010299956639812; /* 1 / log2(10) */
if (dlen > MaxDigits) {
sprintf(sbuf,"integer(~%ld)",dlen - 2); /* center estimage */
len = strlen(sbuf);
if (strreq(len) == Error)
return Error;
StrLoc(*dp2) = alcstr(sbuf,strlen(sbuf));
StrLen(*dp2) = len;
return Success;
}
}
#endif /* LargeInts */
case T_Integer:
case T_Real:
/*
* Form a string representing the number and allocate it.
*/
*dp2 = *dp1; /* don't clobber dp1 */
cvstr(dp2, sbuf);
len = StrLen(*dp2);
if (strreq(len) == Error)
return Error;
StrLoc(*dp2) = alcstr(StrLoc(*dp2), len);
StrLen(*dp2) = len;
return Success;
case T_Cset:
/*
* Check for distinguished csets by looking at the address of
* of the object to image. If one is found, make a string
* naming it and return.
*/
if (BlkLoc(*dp1) == ((union block *)&k_ascii)) {
StrLoc(*dp2) = "&ascii";
StrLen(*dp2) = 6;
return Success;
}
else if (BlkLoc(*dp1) == ((union block *)&k_cset)) {
StrLoc(*dp2) = "&cset";
StrLen(*dp2) = 5;
return Success;
}
else if (BlkLoc(*dp1) == ((union block *)&k_digits)) {
StrLoc(*dp2) = "&digits";
StrLen(*dp2) = 7;
return Success;
}
else if (BlkLoc(*dp1) == ((union block *)&k_lcase)) {
StrLoc(*dp2) = "&lcase";
StrLen(*dp2) = 6;
return Success;
}
else if (BlkLoc(*dp1) == ((union block *)&k_letters)) {
StrLoc(*dp2) = "&letters";
StrLen(*dp2) = 8;
return Success;
}
else if (BlkLoc(*dp1) == ((union block *)&k_ucase)) {
StrLoc(*dp2) = "&ucase";
StrLen(*dp2) = 6;
return Success;
}
/*
* Convert the cset to a string and proceed as is done for
* string images but use a ' rather than " to bound the
* result string.
*/
cvstr(dp1, sbuf);
if (strreq(prescan(dp1) + 2) == Error)
return Error;
len = StrLen(*dp1);
s = StrLoc(*dp1);
outlen = 2;
StrLoc(*dp2) = alcstr("'", (word)(1));
while (len-- > 0)
outlen += doimage(*s++, '\'');
alcstr("'", (word)(1));
StrLen(*dp2) = outlen;
return Success;
case T_File:
/*
* Check for distinguished files by looking at the address of
* of the object to image. If one is found, make a string
* naming it and return.
*/
if ((fd = BlkLoc(*dp1)->file.fd) == stdin) {
StrLen(*dp2) = 6;
StrLoc(*dp2) = "&input";
}
else if (fd == stdout) {
StrLen(*dp2) = 7;
StrLoc(*dp2) = "&output";
}
else if (fd == stderr) {
StrLen(*dp2) = 7;
StrLoc(*dp2) = "&errout";
}
else {
/*
* The file is not a standard one; form a string of the form
* file(nm) where nm is the argument originally given to
* open.
*/
if (strreq(prescan(&BlkLoc(*dp1)->file.fname)+6) == Error)
return Error;
len = StrLen(BlkLoc(*dp1)->file.fname);
s = StrLoc(BlkLoc(*dp1)->file.fname);
outlen = 6;
StrLoc(*dp2) = alcstr("file(", (word)(5));
while (len-- > 0)
outlen += doimage(*s++, '\0');
alcstr(")", (word)(1));
StrLen(*dp2) = outlen;
}
return Success;
case T_Proc:
/*
* Produce one of:
* "procedure name"
* "function name"
* "record constructor name"
*
* Note that the number of dynamic locals is used to determine
* what type of "procedure" is at hand.
*/
len = StrLen(BlkLoc(*dp1)->proc.pname);
s = StrLoc(BlkLoc(*dp1)->proc.pname);
switch ((int)BlkLoc(*dp1)->proc.ndynam) {
default: type = "procedure "; break;
case -1: type = "function "; break;
case -2: type = "record constructor "; break;
}
outlen = strlen(type);
if (strreq(len + outlen) == Error)
return Error;
StrLoc(*dp2) = alcstr(type, outlen);
alcstr(s, len);
StrLen(*dp2) = len + outlen;
return Success;
case T_List:
/*
* Produce:
* "list_m(n)"
* where n is the current size of the list.
*/
bp = BlkLoc(*dp1);
sprintf(sbuf, "list_%ld(%ld)", (long)bp->list.id, (long)bp->list.size);
len = strlen(sbuf);
if (strreq(len) == Error)
return Error;
StrLoc(*dp2) = alcstr(sbuf, len);
StrLen(*dp2) = len;
return Success;
case T_Table:
/*
* Produce:
* "table_m(n)"
* where n is the size of the table.
*/
bp = BlkLoc(*dp1);
sprintf(sbuf, "table_%ld(%ld)", (long)bp->table.id,
(long)bp->table.size);
len = strlen(sbuf);
if (strreq(len) == Error)
return Error;
StrLoc(*dp2) = alcstr(sbuf, len);
StrLen(*dp2) = len;
return Success;
case T_Set:
/*
* Produce "set_m(n)" where n is size of the set.
*/
bp = BlkLoc(*dp1);
sprintf(sbuf, "set_%ld(%ld)", (long)bp->set.id, (long)bp->set.size);
len = strlen(sbuf);
if (strreq(len) == Error)
return Error;
StrLoc(*dp2) = alcstr(sbuf,len);
StrLen(*dp2) = len;
return Success;
case T_Record:
/*
* Produce:
* "record name_m(n)" -- under construction
* where n is the number of fields.
*/
bp = BlkLoc(*dp1);
rnlen = StrLen(bp->record.recdesc->proc.recname);
if (strreq(15 + rnlen) == Error) /* 15 = *"record " + *"(nnnnnn)"*/
return Error;
bp = BlkLoc(*dp1);
sprintf(sbuf, "_%ld(%ld)", (long)bp->record.id,
(long)bp->record.recdesc->proc.nfields);
len = strlen(sbuf);
StrLoc(*dp2) = alcstr("record ", (word)(7));
alcstr(StrLoc(bp->record.recdesc->proc.recname),rnlen);
alcstr(sbuf, len);
StrLen(*dp2) = 7 + len + rnlen;
return Success;
case T_Coexpr:
/*
* Produce:
* "co-expression_m(n)"
* where m is the number of the co-expressions and n is the
* number of results that have been produced.
*/
if (strreq((uword)30) == Error)
return Error;
sprintf(sbuf, "_%ld(%ld)", (long)BlkLoc(*dp1)->coexpr.id,
(long)BlkLoc(*dp1)->coexpr.size);
len = strlen(sbuf);
StrLoc(*dp2) = alcstr("co-expression", (word)(13));
alcstr(sbuf, len);
StrLen(*dp2) = 13 + len;
return Success;
case T_External:
/*
* For now, just produce "external(n)".
*/
sprintf(sbuf, "external(%ld)", (long)BlkLoc(*dp1)->externl.blksize);
len = strlen(sbuf);
if (strreq(len) == Error)
return Error;
StrLoc(*dp2) = alcstr(sbuf, len);
StrLen(*dp2) = len;
return Success;
default:
RetError(123,*dp1);
}
}
/*
* printable(c) -- is c a "printable" character?
*/
int printable(c)
int c;
{
/*
* The following code is operating-system dependent [@rmisc.01].
* Determine if a character is "printable".
*/
#if PORT
return isprint(c);
Deliberate Syntax Error
#endif /* PORT */
#if MVS || VM
#if SASC
return isascii(c) && !iscntrl(c);
#else /* SASC */
return isprint(c);
#endif /* SASC */
#endif /* MVS || VM */
#if AMIGA || ATARI_ST || HIGHC_386 || MACINTOSH || MSDOS || OS2 || UNIX || VMS
return (isascii(c) && isprint(c));
#endif /* AMIGA || ATARI_ST ... */
/*
* End of operating-system specific code.
*/
}
#ifndef AsmOver
/*
* add, sub, mul, neg with overflow check
* all return 1 if ok, 0 if would overflow
*/
/*
* Note: on some systems an improvement in performance can be obtained by
* replacing the C functions that follow by checks written in assembly
* language. To do so, add #define AsmOver to ../h/define.h. If your
* C compiler supports the asm directive, but the new code at the end
* of this section under control of #else. Otherwise put it a separate
* file.
*/
extern int over_flow;
word add(a, b)
word a, b;
{
if ((a ^ b) >= 0 && (a >= 0 ? b > MaxLong - a : b < MinLong - a)) {
over_flow = 1;
return 0;
}
else {
over_flow = 0;
return a + b;
}
}
word sub(a, b)
word a, b;
{
if ((a ^ b) < 0 && (a >= 0 ? b < a - MaxLong : b > a - MinLong)) {
over_flow = 1;
return 0;
}
else {
over_flow = 0;
return a - b;
}
}
word mul(a, b)
word a, b;
{
if (b != 0) {
if ((a ^ b) >= 0) {
if (a >= 0 ? a > MaxLong / b : a < MaxLong / b) {
over_flow = 1;
return 0;
}
}
else if (b != -1 && (a >= 0 ? a > MinLong / b : a < MinLong / b)) {
over_flow = 1;
return 0;
}
}
over_flow = 0;
return a * b;
}
/* MinLong / -1 overflows; need div3 too */
word neg(a)
word a;
{
if (a == MinLong) {
over_flow = 1;
return 0;
}
over_flow = 0;
return -a;
}
#endif /* AsmOver */